package com.zmj.sy.mom.srv.aps.utils.nest;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.IdUtil;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator;
import com.zmj.sy.mom.srv.aps.bean.dto.mes.*;
import com.zmj.sy.mom.srv.aps.bean.entity.log.LogNestExce;
import com.zmj.sy.mom.srv.aps.bean.entity.mes.*;
import com.zmj.sy.mom.srv.aps.bean.entity.order.*;
import com.zmj.sy.mom.srv.aps.bean.entity.third.*;
import com.zmj.sy.mom.srv.aps.bean.vo.aps.ApsNestHexagonItemReqVo;
import com.zmj.sy.mom.srv.aps.bean.vo.nest.NestProPushHexAllReqVo;
import com.zmj.sy.mom.srv.aps.bean.vo.nest.NestProPushHexReqVo;
import com.zmj.sy.mom.srv.aps.bean.vo.nest.NestReceiveReqVo;
import com.zmj.sy.mom.srv.aps.bean.vo.nest.newNest.ReceiveNestExcessReqVo;
import com.zmj.sy.mom.srv.aps.bean.vo.nest.newNest.ReceiveNestMoveReqVo;
import com.zmj.sy.mom.srv.aps.bean.vo.nest.newNest.ReceiveNestPartReqVo;
import com.zmj.sy.mom.srv.aps.bean.vo.nest.newNest.ReceiveNestPlateReqVo;
import com.zmj.sy.mom.srv.aps.bean.vo.plate.UpdateNxolpstatusVo;
import com.zmj.sy.mom.srv.aps.feign.ApsMesFeign;
import com.zmj.sy.mom.srv.aps.mapper.*;
import com.zmj.sy.mom.srv.aps.utils.*;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.io.File;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@RequiredArgsConstructor
@Slf4j
@Component
public class HexagonNestRule extends DefaultNestRule {

    private final SinoCamPushPlanMapper sinoCamPushPlanMapper;

    private final HexagonPackagePushMapper hexagonPackagePushMapper;

    private final OrderMapper orderMapper;

    private final ApsOrderMapper apsOrderMapper;

    private final ApsWorkOrderMapper apsWorkOrderMapper;

    private final OrderPhaseMapper orderPhaseMapper;

    private final ImportErpMappingMapper importErpMappingMapper;

    private final ObjectMapper objectMapper;
    private final ApsMesFeign apsMesFeign;
    private final LogNestExceMapper logNestExceMapper;
    private final PickMapper pickMapper;
    private final SinoCamMapper sinoCamMapper;
    private final SinoCamReceiveNestMapper sinoCamReceiveNestMapper;
    private final SinoCamReceiveNestNestMapper sinoCamReceiveNestNestMapper;
    private final SinoCamReceiveNestPartMapper sinoCamReceiveNestPartMapper;
    private final SinoCamReceiveNestPlateMapper sinoCamReceiveNestPlateMapper;
    private final SinoCamReceiveNestExcessMapper sinoCamReceiveNestExcessMapper;
    private final SinoCamReceiveNestMoveMapper sinoCamReceiveNestMoveMapper;
    private final ApsWorkDetailMapper apsWorkDetailMapper;
    private final PlateMapper plateMapper;
    private final PlatePhaseMapper platePhaseMapper;
    private final WmsPlatePickMapper wmsPlatePickMapper;
    private final SinoCamPushDrawingMapper sinoCamPushDrawingMapper;
    private final WorkDetailTaskMapper workDetailTaskMapper;

    @Value("${project.feign.mes-url-order}")
    private String mesUrlOrder;

    @Value("${project.feign.dxf-download}")
    private String dxfDownload;

    @Value("${project.feign.mes-url-png}")
    private String mesPNG;

    @Value("${project.feign.mes-url-dxf}")
    private String mesDXF;

    @Override
    public String getCode() {
        return NestRule.HEXAGON;
    }

    @Override
    public boolean isPre() {
        return getCode().split(":")[1].equals("1");
    }

    @Override
    public String getSource() {
        return getCode().split(":")[0];
    }

    @Transactional
    public void valid(NestProPushHexAllReqVo reqVo) {

        if(CollUtil.isEmpty(reqVo.getItem())){
            return ;
        }

        List<String> pkgCode = reqVo.getItem().stream().map(ApsNestHexagonItemReqVo::getPkgCode).collect(Collectors.toList());
        List<String> disPkgCode = pkgCode.stream().distinct().collect(Collectors.toList());
        if(pkgCode.size() > disPkgCode.size()){
            throw SyExceptionUtils.e("存在重复的包，请修改包名不重复");
        }

        Integer count = hexagonPackagePushMapper.lambdaQuery()
                .eq(HexagonPackagePush::getMesOrderCode, reqVo.getMesOrderCode())
                .in(HexagonPackagePush::getPackageCode, pkgCode)
                .count();

        if(count > 0){
            throw SyExceptionUtils.e("MES的同一个包不能推送两次，请检查MES的包下是否有数据");
        }

    }

    @Transactional
    @SneakyThrows
    public List<HexagonPackagePush> converterAndSave(NestProPushHexAllReqVo reqVo) {

        Order order = orderMapper.selectById(reqVo.getOrderId());
        if (order.getPushStatus() != 1) {
            throw SyExceptionUtils.e("订单已推送，请查看推送详情");
        }
        Integer count = hexagonPackagePushMapper.lambdaQuery().eq(HexagonPackagePush::getOrderId, reqVo.getOrderId()).count();
        if(count > 0){
            throw SyExceptionUtils.e("订单已推送到海克斯康，如有异常请点击重新推送!");
        }

        List<ApsOrder> apsOrderList = apsOrderMapper.lambdaQuery().eq(ApsOrder::getOrderId, reqVo.getOrderId()).list();

        List<ApsWorkOrder> apsWorkOrderList = apsWorkOrderMapper.lambdaQuery().eq(ApsWorkOrder::getOrderId, reqVo.getOrderId()).list();

        List<OrderPhase> orderPhaseList = orderPhaseMapper.lambdaQuery().eq(OrderPhase::getOrderId, reqVo.getOrderId()).list();
        Map<Integer, List<OrderPhase>> orderPhaseBomIdMap = orderPhaseList.stream().collect(Collectors.groupingBy(OrderPhase::getBomId));

        // 转换对象
        List<HexagonPackagePush> packagePushList = converterHexagonPackagePushList(reqVo, order, apsOrderList, apsWorkOrderList, orderPhaseBomIdMap);

        for (HexagonPackagePush hexagonPackagePush : packagePushList) {
            hexagonPackagePushMapper.insert(hexagonPackagePush);
        }

        order.setPushStatus(2);
        order.setPushType(1);
        order.setOrderStatus(7);
        orderMapper.updateById(order);

        fixPushPlan(reqVo, packagePushList);

        return packagePushList;

    }

    @SneakyThrows
    public List<HexagonPackagePush> converterHexagonPackagePushList(NestProPushHexAllReqVo reqVo, Order o, List<ApsOrder> apsOrderList, List<ApsWorkOrder> apsWorkOrderList, Map<Integer, List<OrderPhase>> orderPhaseBomIdMap) {

        XmlMapper xmlMapper = new XmlMapper();
        xmlMapper.configure(ToXmlGenerator.Feature.WRITE_XML_DECLARATION, true);
        xmlMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        xmlMapper.findAndRegisterModules();

        Map<String, Integer> params = new HashMap<>();
        params.put("Assembly", 1);
        params.put("Platepart", 2);
        params.put("Component", 3);

        apsOrderList.sort(Comparator.comparing(ApsOrder::getSeq));
        Map<Integer, List<ApsWorkOrder>> pidMap = apsWorkOrderList.stream().filter(e -> e.getPid() != null).collect(Collectors.groupingBy(ApsWorkOrder::getPid));
        List<ImportErpMapping> erpMappingList = importErpMappingMapper.lambdaQuery()
                .isNotNull(ImportErpMapping::getMesWorkPhase)
                .isNotNull(ImportErpMapping::getMesWorkCenter)
                .isNotNull(ImportErpMapping::getErpOpCode)
                .isNotNull(ImportErpMapping::getErpOp)
                .list();

        Map<String, Map<String, ImportErpMapping>> collect = erpMappingList.stream()
                .collect(
                        Collectors.groupingBy(ImportErpMapping::getMesWorkPhase,
                                Collectors.toMap(ImportErpMapping::getMesWorkCenter, Function.identity(), (e1, e2) ->
                                        e1.getErpOp().compareTo(e2.getErpOp()) > 0? e1 : e2)
                        )
                );

        List<HexagonPackagePush> rootList = new ArrayList<>();
        int dateIndex = 0;
        for (ApsOrder apsOrder : apsOrderList) {
            MesOrderRootReqDto root = new MesOrderRootReqDto();
            root.setSender("ERP");
            root.setTarget("SPx");
            root.setMsgSegNo(UUID.fastUUID().toString());
            root.setVersion("1.0");
            root.setDateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            root.setAction("BOM");

            MesOrderDataReqDto data = new MesOrderDataReqDto();
            root.setData(data);
            MesOrderDataCustomerDataReqDto customerData = new MesOrderDataCustomerDataReqDto();
            customerData.setName(reqVo.getCustName());
            customerData.setCustomerNumber(reqVo.getCustCode());
            customerData.setOffsetX1("0");
            customerData.setOffsetY("90.000");
            customerData.setRotation("0");

            MesOrderDataCustomerOrderDataReqDto customerOrderData = new MesOrderDataCustomerOrderDataReqDto();
            customerOrderData.setOrderName(reqVo.getMesOrderCode());
            customerOrderData.setInfo(o.getMaterName());
            String pkgCode = null;
            if(CollUtil.isNotEmpty(reqVo.getItem()) && dateIndex < reqVo.getItem().size()){
                if(reqVo.getItem().get(dateIndex).getDeliveryDate() != null){
                    customerOrderData.setDueDate(reqVo.getItem().get(dateIndex).getDeliveryDate().toString());
                } else {
                    customerOrderData.setDueDate(o.getDeliveryDateTime().toLocalDate().toString());
                }
                if(reqVo.getItem().get(dateIndex).getPkgCode() != null){
                    pkgCode = reqVo.getItem().get(dateIndex).getPkgCode();
                } else {
                    pkgCode = PkgUtils.gen(apsOrder.getSeq());
                }
            } else {
                customerOrderData.setDueDate(o.getDeliveryDateTime().toLocalDate().toString());
                pkgCode = PkgUtils.gen(apsOrder.getSeq());
            }
            dateIndex++;

            customerOrderData.setInfo(o.getMaterName());

            data.setCustomerOrderData(customerOrderData);
            data.setCustomerData(customerData);
            List<MesOrderDataAssemblyReqDto> assemblyList = new ArrayList<>();
            data.setAssembly(assemblyList);

            MesOrderDataAssemblyReqDto c = apsWorkOrderToAss(o, apsOrder, pkgCode);
            assemblyList.add(c);

            Optional<ApsWorkOrder> first = apsWorkOrderList.stream().filter(e -> e.getPid() == null && e.getApsOrderId().equals(apsOrder.getId())).findFirst();
            if (!first.isPresent()) {
                continue;
            }

            ApsWorkOrder top = first.get();

            Map<Integer, MesOrderDataAssemblyReqDto> hashMap = new HashMap<>();
            List<ApsWorkOrder> parent = new ArrayList<>();
            if(o.getSerialCode().equals(top.getPlmId())){
                List<ApsWorkOrder> apsWorkOrder = apsWorkOrderList.stream().filter(e -> e.getPid() != null && e.getPid().equals(top.getId())).collect(Collectors.toList());
                for (ApsWorkOrder workOrder : apsWorkOrder) {
                    workOrder.setAssemblyPath("/" + workOrder.getPlmId());
                }
                parent.addAll(apsWorkOrder);
            } else {
                parent.add(top);
                top.setAssemblyPath("/" + top.getPlmId());
            }
            while(true){

                List<ApsWorkOrder> temp = new ArrayList<>();
                for (ApsWorkOrder assembly : parent) {
                    MesOrderDataAssemblyReqDto c1 = null;
                    if(assembly.getMaterType().equals("Assembly")){
                        c1 = apsWorkOrderToAss(o, apsOrder, assembly);
                        hashMap.put(assembly.getId(), c1);
                        if (assembly.getPid() == null || hashMap.get(assembly.getPid()) == null) {
                            if (c.getAssembly() == null) {
                                c.setAssembly(new ArrayList<>());
                            }
                            c.getAssembly().add(c1);
                        } else {
                            if (hashMap.get(assembly.getPid()).getAssembly() == null) {
                                hashMap.get(assembly.getPid()).setAssembly(new ArrayList<>());
                            }
                            hashMap.get(assembly.getPid()).getAssembly().add(c1);
                        }

                        List<ApsWorkOrder> apsWorkOrders = pidMap.get(assembly.getId());
                        if (CollUtil.isNotEmpty(apsWorkOrders)) {
                            for (ApsWorkOrder apsWorkOrder : apsWorkOrders) {
                                apsWorkOrder.setAssemblyPath(assembly.getAssemblyPath() + "/" + apsWorkOrder.getPlmId());
                            }
                            temp.addAll(apsWorkOrders);
                        }

                        List<OrderPhase> phaseList = orderPhaseBomIdMap.get(assembly.getBomId());
                        List<MesOrderDataWorkDetailReqDto> list = apsWorkDetailToWorkDetail( assembly, phaseList,collect);
                        c1.setWorkDetails(list);
                    } else if(assembly.getMaterType().equals("Platepart")){
                        MesOrderDataPlatepartReqDto platepart = apsWorkOrderToPlatePart(o, assembly);
                        MesOrderDataAssemblyReqDto pp = hashMap.get(assembly.getPid());
                        if(pp.getPlatepart() == null){
                            pp.setPlatepart(new ArrayList<>());
                        }
                        pp.getPlatepart().add(platepart);
                        List<OrderPhase> phaseList = orderPhaseBomIdMap.get(assembly.getBomId());
                        List<MesOrderDataWorkDetailReqDto> list = apsWorkDetailToWorkDetail( assembly, phaseList,collect);
                        platepart.setWorkDetails(list);
                    } else if(assembly.getMaterType().equals("Component")){
                        MesOrderDataComponentReqDto component = apsWorkOrderToComponent(o, assembly);
                        MesOrderDataAssemblyReqDto pp = hashMap.get(assembly.getPid());
                        if(pp.getComponent() == null){
                            pp.setComponent(new ArrayList<>());
                        }
                        pp.getComponent().add(component);
                        List<MesOrderDataWorkDetailReqDto> list = new ArrayList<>();
                        MesOrderDataWorkDetailReqDto mesOrderDataWorkDetailReqDto = new MesOrderDataWorkDetailReqDto();
                        mesOrderDataWorkDetailReqDto.setId(1);
                        mesOrderDataWorkDetailReqDto.setWorkTime("0");
                        mesOrderDataWorkDetailReqDto.setWorkPhase("WL");
                        mesOrderDataWorkDetailReqDto.setMesWorkCenter("2-4_LLGW_01");
                        list.add(mesOrderDataWorkDetailReqDto);
                        component.setWorkDetails(list);
                    }
                }
                if(CollUtil.isEmpty(temp)){
                    break;
                }

                parent = temp;
                parent.sort((e1, e2) ->{
                    int i = params.get(e1.getMaterType()).compareTo(params.get(e1.getMaterType()));
                    if(i != 0){
                        return i;
                    }

                    return e1.getPlmId().compareTo(e2.getPlmId());
                });

            }

            HexagonPackagePush hexagonPackagePush = new HexagonPackagePush();
            hexagonPackagePush.setOrderId(reqVo.getOrderId());
            hexagonPackagePush.setApsOrderId(apsOrder.getId());
            hexagonPackagePush.setStatus(1);
            hexagonPackagePush.setPackageCode(c.getAssemblyName());

            String filePath = "/home/storage/hexagon/push/%s/%s.txt";
            String yyyyMM = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMM"));
            String path = String.format(filePath, yyyyMM, IdUtil.fastSimpleUUID());

            FileUtils.writeStringToFile(new File(path), xmlMapper.writeValueAsString(root), "UTF-8");

            hexagonPackagePush.setRequestPath(path);
            hexagonPackagePush.setCustName(reqVo.getCustName());
            hexagonPackagePush.setCustCode(reqVo.getCustCode());
            hexagonPackagePush.setMesOrderCode(reqVo.getMesOrderCode());
            hexagonPackagePush.setMesOrderId(reqVo.getMesOrderId());
            hexagonPackagePush.setEndDate(LocalDate.parse(customerOrderData.getDueDate(), DateTimeFormatter.ofPattern("yyyy-MM-dd")));

            rootList.add(hexagonPackagePush);

        }
        return rootList;
    }

    public MesOrderDataAssemblyReqDto apsWorkOrderToAss(Order o, ApsOrder apsOrder, String pkgCode) {
        MesOrderDataAssemblyReqDto assembly = new MesOrderDataAssemblyReqDto();
        assembly.setAssemblyName(pkgCode);
        assembly.setWorkChain("");
        assembly.setPartCount(String.valueOf(apsOrder.getOrderQty()));
        assembly.setInfo("Workpackage");
        assembly.setErpId("");
        assembly.setConstructNo("");
        assembly.setConstructOrderNo("");

        return assembly;
    }

    public MesOrderDataAssemblyReqDto apsWorkOrderToAss(Order o, ApsOrder apsOrder, ApsWorkOrder apsWorkOrder) {
        MesOrderDataAssemblyReqDto assembly = new MesOrderDataAssemblyReqDto();
        assembly.setAssemblyName(apsWorkOrder.getPlmId());
        assembly.setWorkChain(apsWorkOrder.getWorkChain());
        assembly.setPartCount(String.valueOf(apsWorkOrder.getPartCount().intValue()));
        assembly.setInfo(apsWorkOrder.getMaterName());
        assembly.setDrawing(apsWorkOrder.getDrawing());
        assembly.setPlmId(apsWorkOrder.getPlmId());
        if(!StringUtils.hasText(assembly.getDrawing())){
            assembly.setDrawing(assembly.getPlmId());
        }
        assembly.setWeight(apsWorkOrder.getMaterWeight());
        assembly.setErpId(apsWorkOrder.getErpCode());
        assembly.setConstructNo(o.getConstructNo());
        assembly.setConstructOrderNo(apsWorkOrder.getWorkOrderCode());
        assembly.setAssemblyPath(apsWorkOrder.getAssemblyPath().replaceFirst("/Z188-LS_170", ""));

        return assembly;
    }

    public List<MesOrderDataWorkDetailReqDto> apsWorkDetailToWorkDetail(ApsWorkOrder assembly, List<OrderPhase> orderPhaseList, Map<String, Map<String, ImportErpMapping>> collect) {
        if (CollUtil.isEmpty(orderPhaseList)){
            return null;
        }
        List<MesOrderDataWorkDetailReqDto> list = new ArrayList<>();
        orderPhaseList.removeIf(e-> e.getPhaseCode().equals(WorkshopProp.LL_PHASE_CODE) || e.getPhaseCode().equals(WorkshopProp.KJ_PHASE_CODE));
        orderPhaseList.sort(Comparator.comparing(OrderPhase::getPhaseSeq));
        for (OrderPhase orderPhase : orderPhaseList) {
            MesOrderDataWorkDetailReqDto workDetail = new MesOrderDataWorkDetailReqDto();
            workDetail.setId(list.size() + 1);
            workDetail.setWorkTime(new BigDecimal(orderPhase.getOriWorkTime()).divide(new BigDecimal("60"), 4, RoundingMode.HALF_UP).toPlainString());
            workDetail.setWorkPhase(orderPhase.getPhaseCode());
            workDetail.setMesWorkCenter(orderPhase.getWorkGroupNumber());
            workDetail.setErpSeq(workDetail.getId());
            workDetail.setErpOp(orderPhase.getPhaseCode());
            workDetail.setErpOpCode(orderPhase.getWorkGroupNumber());
            list.add(workDetail);
        }

        return list;
    }

    public MesOrderDataPlatepartReqDto apsWorkOrderToPlatePart(Order o, ApsWorkOrder apsWorkOrder) {
        MesOrderDataPlatepartReqDto platepart = new MesOrderDataPlatepartReqDto();
        platepart.setName(apsWorkOrder.getPlmId());
        platepart.setWorkChain(apsWorkOrder.getWorkChain());
        platepart.setType("Important");
        platepart.setInfo(apsWorkOrder.getMaterHigh().toString());
        platepart.setWeight(apsWorkOrder.getMaterWeight().toPlainString());
        platepart.setDrawing(apsWorkOrder.getDrawing());
        platepart.setPlmId(apsWorkOrder.getPlmId());
        if(!StringUtils.hasText(platepart.getDrawing())){
            platepart.setDrawing(platepart.getPlmId());
        }
        platepart.setErpId(apsWorkOrder.getErpCode());
        platepart.setCount(String.valueOf(apsWorkOrder.getPartCount().intValue()));
        platepart.setInfo(apsWorkOrder.getMaterName());
        platepart.setMaterial(apsWorkOrder.getTexture());
        platepart.setConstructNo(o.getConstructNo());
        platepart.setConstructOrderNo(apsWorkOrder.getWorkOrderCode());
        platepart.setAssemblyPath(apsWorkOrder.getAssemblyPath());
        platepart.setThickness(apsWorkOrder.getMaterHigh().toString());
        return platepart;
    }

    public MesOrderDataComponentReqDto apsWorkOrderToComponent(Order o, ApsWorkOrder apsWorkOrder) {
        MesOrderDataComponentReqDto component = new MesOrderDataComponentReqDto();
        component.setName(apsWorkOrder.getPlmId());
        component.setWorkChain(apsWorkOrder.getWorkChain());
        if(apsWorkOrder.getMaterWeight() != null){
            component.setWeight(apsWorkOrder.getMaterWeight().toPlainString());
        }
        component.setPlmId(apsWorkOrder.getPlmId());
        component.setDrawing(apsWorkOrder.getDrawing());
        if(!StringUtils.hasText(component.getDrawing())){
            component.setDrawing(component.getPlmId());
        }
        component.setErpId(apsWorkOrder.getErpCode());
        component.setCount(String.valueOf(apsWorkOrder.getPartCount().intValue()));
        component.setInfo(apsWorkOrder.getMaterName());
        component.setConstructNo(o.getConstructNo());
        component.setConstructOrderNo(apsWorkOrder.getWorkOrderCode());
        component.setAssemblyPath(apsWorkOrder.getAssemblyPath());
        return component;
    }

    @Transactional
    public void fixPushPlan(NestProPushHexAllReqVo reqVo, List<HexagonPackagePush> hexagonPackagePushList) {
        Integer orderId = reqVo.getOrderId();
        Map<Integer, HexagonPackagePush> hexagonPackagePushMap = hexagonPackagePushList.stream().collect(Collectors.toMap(HexagonPackagePush::getApsOrderId, e -> e));
        List<SinoCamPushPlan> pushPlanList = sinoCamPushPlanMapper.lambdaQuery().eq(SinoCamPushPlan::getOrderId, orderId).list();
        for (SinoCamPushPlan pushPlan : pushPlanList) {
            HexagonPackagePush push = hexagonPackagePushMap.get(pushPlan.getApsOrderId());
            pushPlan.setPushType(1);
            pushPlan.setMesOrderCode(push.getMesOrderCode());
            pushPlan.setMesPkgCode(push.getPackageCode());
            pushPlan.setPath(push.getPackageCode() + pushPlan.getPath());
            sinoCamPushPlanMapper.updateById(pushPlan);
        }
    }

    @Async("taskExecutor")
    public void sendToMesAll(NestProPushHexAllReqVo reqVo, List<HexagonPackagePush> packagePushList) {
        for (HexagonPackagePush hexagonPackagePush : packagePushList) {
            sendToMes(reqVo, hexagonPackagePush);
        }
    }

    @SneakyThrows
    public void sendToMes(NestProPushHexAllReqVo reqVo, HexagonPackagePush packagePushList) {
        HexagonPackagePush p = new HexagonPackagePush();
        p.setId(packagePushList.getId());
        p.setStatus(2);
        p.setErrorMsg("");
        p.setResponsePath(null);

        hexagonPackagePushMapper.updateById(p);
        long start = System.currentTimeMillis();

        String requestBody = FileUtils.readFileToString(new File(packagePushList.getRequestPath()), "UTF-8");

        log.info("MES-订单导入-请求：{}",requestBody);

        try (HttpResponse execute = HttpUtil.createPost(mesUrlOrder)
                .contentType("application/xml")
                .header("Accept-Encoding", "gzip, deflate, br")
                .header("Accept", "*/*")
                .body(requestBody, "application/xml")
                .execute()){

            String body = execute.body();

            log.info("MES-订单导入-响应：{}",body);

            String path = FileStorageUtils.getFilePath(FileStorageUtils.NEST_HEXAGON_TYPE);

            FileUtils.writeStringToFile(new File(path), body,"UTF-8");
            p.setResponsePath(path);


            XmlMapper xmlMapper = new XmlMapper();
            JsonNode jsonNode = xmlMapper.readTree(body);
            if(!jsonNode.get("StatusCode").asText().equals("200")){
                p.setStatus(4);
                if(jsonNode.get("ErrorMessage") != null && jsonNode.get("ErrorMessage").asText().length() > 100){
                    p.setErrorMsg(jsonNode.get("ErrorMessage").asText().substring(0, 100));
                } else {
                    p.setErrorMsg(jsonNode.get("ErrorMessage").asText());
                }
            }else {
                p.setStatus(3);
                p.setWorkTime(System.currentTimeMillis() - start);
            }
        } catch (Exception e) {
            e.printStackTrace();
            p.setStatus(4);
            p.setWorkTime(System.currentTimeMillis() - start);
        } finally {
            hexagonPackagePushMapper.updateById(p);
        }

        // 如果有推送中的，就为推送中
        Order order = orderMapper.selectById(packagePushList.getOrderId());

        Integer count = hexagonPackagePushMapper.lambdaQuery()
                .eq(HexagonPackagePush::getOrderId, packagePushList.getOrderId())
                .in(HexagonPackagePush::getStatus, 1,2)
                .count();
        if (count > 0) {
            order.setPushStatus(2);
            orderMapper.updateById(order);
            return ;
        }

        count = hexagonPackagePushMapper.lambdaQuery()
                .eq(HexagonPackagePush::getOrderId, packagePushList.getOrderId())
                .ne(HexagonPackagePush::getStatus, 3)
                .count();
        if (count > 0) {
            order.setPushStatus(4); // 失败
            orderMapper.updateById(order);
            sinoCamPushPlanMapper.lambdaUpdate()
                    .eq(SinoCamPushPlan::getApsOrderId, packagePushList.getApsOrderId())
                    .set(SinoCamPushPlan::getStatus, 5)
                    .set(SinoCamPushPlan::getModifyDateTime, LocalDateTime.now())
                    .set(SinoCamPushPlan::getModifyUsername, SySecurityUtils.getUserCode())
                    .update();
        } else {
            order.setPushStatus(3); // 成功
            orderMapper.updateById(order);
            sinoCamPushPlanMapper.lambdaUpdate()
                    .eq(SinoCamPushPlan::getApsOrderId, packagePushList.getApsOrderId())
                    .set(SinoCamPushPlan::getStatus, 4)
                    .set(SinoCamPushPlan::getModifyDateTime, LocalDateTime.now())
                    .set(SinoCamPushPlan::getModifyUsername, SySecurityUtils.getUserCode())
                    .update();
        }

    }

    @Transactional
    @SneakyThrows
    public List<HexagonPackagePush> converterAndSave(NestProPushHexReqVo reqVo, List<SinoCamPushPlan> pushPlanList) {

        Order order = orderMapper.selectById(reqVo.getOrderId());

        List<ApsWorkDetail> apsWorkDetailList = apsWorkDetailMapper.lambdaQuery()
                .in(ApsWorkDetail::getId, pushPlanList.stream().map(SinoCamPushPlan::getNestPlanId).collect(Collectors.toList()))
                .list();

        List<ApsOrder> apsOrderList = apsOrderMapper.lambdaQuery()
                .eq(ApsOrder::getOrderId, reqVo.getOrderId())
                .list();

        List<ApsOrder> apsOrderChooseList = apsOrderMapper.lambdaQuery()
                .eq(ApsOrder::getOrderId, reqVo.getOrderId())
                .in(ApsOrder::getId, apsWorkDetailList.stream().map(ApsWorkDetail::getApsOrderId).collect(Collectors.toList()))
                .list();

        List<ApsWorkOrder> apsWorkOrderList = apsWorkOrderMapper.lambdaQuery()
                .eq(ApsWorkOrder::getOrderId, reqVo.getOrderId())
                .list();

        List<ApsWorkOrder> apsWorkOrderChooseList = apsWorkOrderMapper.lambdaQuery()
                .eq(ApsWorkOrder::getOrderId, reqVo.getOrderId())
                .in(ApsWorkOrder::getId, apsWorkDetailList.stream().map(ApsWorkDetail::getApsWorkOrderId).collect(Collectors.toList()))
                .list();

        List<OrderPhase> orderPhaseList = orderPhaseMapper.lambdaQuery()
                .eq(OrderPhase::getOrderId, reqVo.getOrderId())
                .in(OrderPhase::getBomId, apsWorkOrderChooseList.stream().map(ApsWorkOrder::getBomId).collect(Collectors.toList()))
                .list();
        Map<Integer, List<OrderPhase>> orderPhaseBomIdMap = orderPhaseList.stream().collect(Collectors.groupingBy(OrderPhase::getBomId));

        // 转换对象
        List<HexagonPackagePush> packagePushList = converterHexagonPackagePushList(reqVo, order, apsOrderList, apsWorkOrderList, orderPhaseBomIdMap, apsOrderChooseList, apsWorkOrderChooseList);

        order.setPushStatus(2);
        order.setOrderStatus(7);
        orderMapper.updateById(order);

        fixPushPlan(reqVo, packagePushList);

        return packagePushList;

    }

    @SneakyThrows
    public List<HexagonPackagePush> converterHexagonPackagePushList(NestProPushHexReqVo reqVo, Order o, List<ApsOrder> apsOrderList, List<ApsWorkOrder> apsWorkOrderList, Map<Integer, List<OrderPhase>> orderPhaseBomIdMap, List<ApsOrder> apsOrderChooseList, List<ApsWorkOrder> apsWorkOrderChooseList) {

        // 先单独将所有包的关联关系写入表中
        // 再按照选中计划的包及工单等信息写入关联关系表的请求体路径参数中

        List<Integer> chooseIds = apsWorkOrderChooseList.stream().map(ApsWorkOrder::getId).collect(Collectors.toList());
        List<Integer> allPids = apsWorkOrderList.stream().map(ApsWorkOrder::getPid).collect(Collectors.toList());
        List<ApsWorkOrder> apsWorkOrderCheckList = apsWorkOrderList.stream().filter(e -> !(!allPids.contains(e.getId()) && !chooseIds.contains(e.getId()))).collect(Collectors.toList());

        List<HexagonPackagePush> hexPushList = addInfoToHexPush(reqVo, o, apsOrderList);
        Map<Integer, HexagonPackagePush> hexPushMap = hexPushList.stream().collect(Collectors.toMap(HexagonPackagePush::getApsOrderId, e -> e));

        XmlMapper xmlMapper = new XmlMapper();
        xmlMapper.configure(ToXmlGenerator.Feature.WRITE_XML_DECLARATION, true);
        xmlMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        xmlMapper.findAndRegisterModules();

        Map<String, Integer> params = new HashMap<>();
        params.put("Assembly", 1);
        params.put("Platepart", 2);
        params.put("Component", 3);

        apsOrderChooseList.sort(Comparator.comparing(ApsOrder::getSeq));
        Map<Integer, List<ApsWorkOrder>> pidMap = apsWorkOrderCheckList.stream().filter(e -> e.getPid() != null).collect(Collectors.groupingBy(ApsWorkOrder::getPid));
        List<ImportErpMapping> erpMappingList = importErpMappingMapper.lambdaQuery()
                .isNotNull(ImportErpMapping::getMesWorkPhase)
                .isNotNull(ImportErpMapping::getMesWorkCenter)
                .isNotNull(ImportErpMapping::getErpOpCode)
                .isNotNull(ImportErpMapping::getErpOp)
                .list();

        Map<String, Map<String, ImportErpMapping>> collect = erpMappingList.stream()
                .collect(
                        Collectors.groupingBy(ImportErpMapping::getMesWorkPhase,
                                Collectors.toMap(ImportErpMapping::getMesWorkCenter, Function.identity(), (e1, e2) ->
                                        e1.getErpOp().compareTo(e2.getErpOp()) > 0 ? e1 : e2)
                        )
                );

        List<HexagonPackagePush> rootList = new ArrayList<>();
        int dateIndex = 0;

        for (ApsOrder apsOrder : apsOrderChooseList) {

            MesOrderRootReqDto root = new MesOrderRootReqDto();
            root.setSender("ERP");
            root.setTarget("SPx");
            root.setMsgSegNo(UUID.fastUUID().toString());
            root.setVersion("1.0");
            root.setDateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            root.setAction("BOM");

            MesOrderDataReqDto data = new MesOrderDataReqDto();
            root.setData(data);
            MesOrderDataCustomerDataReqDto customerData = new MesOrderDataCustomerDataReqDto();
            customerData.setName(reqVo.getCustName());
            customerData.setCustomerNumber(reqVo.getCustCode());
            customerData.setOffsetX1("0");
            customerData.setOffsetY("90.000");
            customerData.setRotation("0");

            MesOrderDataCustomerOrderDataReqDto customerOrderData = new MesOrderDataCustomerOrderDataReqDto();
            customerOrderData.setOrderName(reqVo.getMesOrderCode());
            customerOrderData.setInfo(o.getMaterName());
            String pkgCode = null;
            if(CollUtil.isNotEmpty(reqVo.getItem()) && dateIndex < reqVo.getItem().size()){
                if(reqVo.getItem().get(dateIndex).getDeliveryDate() != null){
                    customerOrderData.setDueDate(reqVo.getItem().get(dateIndex).getDeliveryDate().toString());
                } else {
                    customerOrderData.setDueDate(o.getDeliveryDateTime().toLocalDate().toString());
                }
                if(reqVo.getItem().get(dateIndex).getPkgCode() != null){
                    pkgCode = reqVo.getItem().get(dateIndex).getPkgCode();
                } else {
                    pkgCode = PkgUtils.gen(apsOrder.getSeq());
                }
            } else {
                customerOrderData.setDueDate(o.getDeliveryDateTime().toLocalDate().toString());
                pkgCode = PkgUtils.gen(apsOrder.getSeq());
            }
            dateIndex++;

            customerOrderData.setInfo(o.getMaterName());

            data.setCustomerOrderData(customerOrderData);
            data.setCustomerData(customerData);
            List<MesOrderDataAssemblyReqDto> assemblyList = new ArrayList<>();
            data.setAssembly(assemblyList);

            MesOrderDataAssemblyReqDto c = apsWorkOrderToAss(o, apsOrder, pkgCode);
            assemblyList.add(c);

            Optional<ApsWorkOrder> first = apsWorkOrderCheckList.stream().filter(e -> e.getPid() == null && e.getApsOrderId().equals(apsOrder.getId())).findFirst();
            if (!first.isPresent()) {
                continue;
            }

            ApsWorkOrder top = first.get();

            Map<Integer, MesOrderDataAssemblyReqDto> hashMap = new HashMap<>();
            List<ApsWorkOrder> parent = new ArrayList<>();
            if(o.getSerialCode().equals(top.getPlmId())){
                List<ApsWorkOrder> apsWorkOrder = apsWorkOrderCheckList.stream().filter(e -> e.getPid() != null && e.getPid().equals(top.getId())).collect(Collectors.toList());
                for (ApsWorkOrder workOrder : apsWorkOrder) {
                    workOrder.setAssemblyPath("/" + workOrder.getPlmId());
                }
                parent.addAll(apsWorkOrder);
            } else {
                parent.add(top);
                top.setAssemblyPath("/" + top.getPlmId());
            }
            while(true){

                List<ApsWorkOrder> temp = new ArrayList<>();
                for (ApsWorkOrder assembly : parent) {
                    MesOrderDataAssemblyReqDto c1 = null;
                    if(assembly.getMaterType().equals("Assembly")){
                        c1 = apsWorkOrderToAss(o, apsOrder, assembly);
                        hashMap.put(assembly.getId(), c1);
                        if (assembly.getPid() == null || hashMap.get(assembly.getPid()) == null) {
                            if (c.getAssembly() == null) {
                                c.setAssembly(new ArrayList<>());
                            }
                            c.getAssembly().add(c1);
                        } else {
                            if (hashMap.get(assembly.getPid()).getAssembly() == null) {
                                hashMap.get(assembly.getPid()).setAssembly(new ArrayList<>());
                            }
                            hashMap.get(assembly.getPid()).getAssembly().add(c1);
                        }

                        List<ApsWorkOrder> apsWorkOrders = pidMap.get(assembly.getId());
                        if (CollUtil.isNotEmpty(apsWorkOrders)) {
                            for (ApsWorkOrder apsWorkOrder : apsWorkOrders) {
                                apsWorkOrder.setAssemblyPath(assembly.getAssemblyPath() + "/" + apsWorkOrder.getPlmId());
                            }
                            temp.addAll(apsWorkOrders);
                        }

                        List<OrderPhase> phaseList = orderPhaseBomIdMap.get(assembly.getBomId());
                        List<MesOrderDataWorkDetailReqDto> list = apsWorkDetailToWorkDetail( assembly, phaseList,collect);
                        c1.setWorkDetails(list);
                    } else if(assembly.getMaterType().equals("Platepart")){
                        MesOrderDataPlatepartReqDto platepart = apsWorkOrderToPlatePart(o, assembly);
                        MesOrderDataAssemblyReqDto pp = hashMap.get(assembly.getPid());
                        if(pp.getPlatepart() == null){
                            pp.setPlatepart(new ArrayList<>());
                        }
                        pp.getPlatepart().add(platepart);
                        List<OrderPhase> phaseList = orderPhaseBomIdMap.get(assembly.getBomId());
                        List<MesOrderDataWorkDetailReqDto> list = apsWorkDetailToWorkDetail( assembly, phaseList,collect);
                        platepart.setWorkDetails(list);
                    } else if(assembly.getMaterType().equals("Component")){
                        MesOrderDataComponentReqDto component = apsWorkOrderToComponent(o, assembly);
                        MesOrderDataAssemblyReqDto pp = hashMap.get(assembly.getPid());
                        if(pp.getComponent() == null){
                            pp.setComponent(new ArrayList<>());
                        }
                        pp.getComponent().add(component);
                        List<MesOrderDataWorkDetailReqDto> list = new ArrayList<>();
                        MesOrderDataWorkDetailReqDto mesOrderDataWorkDetailReqDto = new MesOrderDataWorkDetailReqDto();
                        mesOrderDataWorkDetailReqDto.setId(1);
                        mesOrderDataWorkDetailReqDto.setWorkTime("0");
                        mesOrderDataWorkDetailReqDto.setWorkPhase("WL");
                        mesOrderDataWorkDetailReqDto.setMesWorkCenter("2-4_LLGW_01");
                        list.add(mesOrderDataWorkDetailReqDto);
                        component.setWorkDetails(list);
                    }
                }
                if(CollUtil.isEmpty(temp)){
                    break;
                }

                parent = temp;
                parent.sort((e1, e2) ->{
                    int i = params.get(e1.getMaterType()).compareTo(params.get(e1.getMaterType()));
                    if(i != 0){
                        return i;
                    }

                    return e1.getPlmId().compareTo(e2.getPlmId());
                });

            }

            HexagonPackagePush hexagonPackagePush = hexPushMap.get(apsOrder.getId());
            hexagonPackagePush.setOrderId(reqVo.getOrderId());
            hexagonPackagePush.setApsOrderId(apsOrder.getId());
            hexagonPackagePush.setStatus(1);
            hexagonPackagePush.setPackageCode(c.getAssemblyName());

            String filePath = "/home/storage/hexagon/push/%s/%s.txt";
            String yyyyMM = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMM"));
            String path = String.format(filePath, yyyyMM, IdUtil.fastSimpleUUID());

            FileUtils.writeStringToFile(new File(path), xmlMapper.writeValueAsString(root), "UTF-8");

            hexagonPackagePush.setRequestPath(path);
            hexagonPackagePush.setCustName(reqVo.getCustName());
            hexagonPackagePush.setCustCode(reqVo.getCustCode());
            hexagonPackagePush.setMesOrderCode(reqVo.getMesOrderCode());
            hexagonPackagePush.setMesOrderId(reqVo.getMesOrderId());
            hexagonPackagePush.setEndDate(LocalDate.parse(customerOrderData.getDueDate(), DateTimeFormatter.ofPattern("yyyy-MM-dd")));

            hexagonPackagePushMapper.updateById(hexagonPackagePush);

            rootList.add(hexagonPackagePush);

        }

        return rootList;
    }

    @Transactional(propagation = Propagation.NESTED)
    public List<HexagonPackagePush> addInfoToHexPush(NestProPushHexReqVo reqVo, Order o, List<ApsOrder> apsOrderList) {
        List<HexagonPackagePush> hexagonPackagePushList = hexagonPackagePushMapper.lambdaQuery().eq(HexagonPackagePush::getOrderId, o.getId()).list();
        if (CollUtil.isNotEmpty(hexagonPackagePushList)) {
            return hexagonPackagePushList;
        }

//        Integer count = hexagonPackagePushMapper.lambdaQuery().eq(HexagonPackagePush::getMesOrderId, reqVo.getMesOrderId()).count();
        LambdaQueryWrapper<HexagonPackagePush> qw = new LambdaQueryWrapper<>();
        qw.eq(HexagonPackagePush::getMesOrderId, reqVo.getMesOrderId());
        List<String> pkgCodeList = reqVo.getItem().stream().map(ApsNestHexagonItemReqVo::getPkgCode).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(pkgCodeList)) {
            qw.in(HexagonPackagePush::getPackageCode, pkgCodeList);
        } else {
            qw.in(HexagonPackagePush::getPackageCode, apsOrderList.stream().map(e-> PkgUtils.gen(e.getSeq())).collect(Collectors.toList()));
        }
        Integer count = hexagonPackagePushMapper.selectCount(qw);
        if (count > 0) {
            throw SyExceptionUtils.e("不支持推送到该MES施工号下：" + reqVo.getMesOrderCode());
        }

        int dateIndex = 0;
        for (ApsOrder apsOrder : apsOrderList) {
            HexagonPackagePush pushVo = new HexagonPackagePush();

            String pkgCode = null;
            if(CollUtil.isNotEmpty(reqVo.getItem()) && dateIndex < reqVo.getItem().size()){
                if(reqVo.getItem().get(dateIndex).getDeliveryDate() != null){
                    pushVo.setEndDate(reqVo.getItem().get(dateIndex).getDeliveryDate());
                } else {
                    pushVo.setEndDate(o.getDeliveryDateTime().toLocalDate());
                }
                if(reqVo.getItem().get(dateIndex).getPkgCode() != null){
                    pkgCode = reqVo.getItem().get(dateIndex).getPkgCode();
                } else {
                    pkgCode = PkgUtils.gen(apsOrder.getSeq());
                }
            } else {
                pushVo.setEndDate(o.getDeliveryDateTime().toLocalDate());
                pkgCode = PkgUtils.gen(apsOrder.getSeq());
            }
            dateIndex++;

            pushVo.setOrderId(reqVo.getOrderId());
            pushVo.setApsOrderId(apsOrder.getId());
            pushVo.setStatus(1);
            pushVo.setPackageCode(pkgCode);
            pushVo.setCustName(reqVo.getCustName());
            pushVo.setCustCode(reqVo.getCustCode());
            pushVo.setMesOrderCode(reqVo.getMesOrderCode());
            pushVo.setMesOrderId(reqVo.getMesOrderId());

            hexagonPackagePushList.add(pushVo);
        }

        for (HexagonPackagePush hexagonPackagePush : hexagonPackagePushList) {
            hexagonPackagePushMapper.insert(hexagonPackagePush);
        }

        return hexagonPackagePushList;
    }

    @Transactional
    public void fixPushPlan(NestProPushHexReqVo reqVo, List<HexagonPackagePush> packagePushList) {
        Map<Integer, HexagonPackagePush> hexagonPackagePushMap = packagePushList.stream().collect(Collectors.toMap(HexagonPackagePush::getApsOrderId, e -> e));
        List<SinoCamPushPlan> pushPlanList = sinoCamPushPlanMapper.lambdaQuery().in(SinoCamPushPlan::getNestPlanId, reqVo.getNestPlanId()).list();
        for (SinoCamPushPlan pushPlan : pushPlanList) {
            HexagonPackagePush push = hexagonPackagePushMap.get(pushPlan.getApsOrderId());
            if (ObjectUtils.isEmpty(push)) {
                throw SyExceptionUtils.e("请检查推送的海克斯康施工单号。");
            }
            pushPlan.setPushType(1);
            pushPlan.setMesOrderCode(push.getMesOrderCode());
            pushPlan.setMesPkgCode(push.getPackageCode());
            pushPlan.setPath(push.getPackageCode() + pushPlan.getPath());
            sinoCamPushPlanMapper.updateById(pushPlan);
        }
    }

    @Async("taskExecutor")
    public void sendToMesAll(NestProPushHexReqVo reqVo, List<HexagonPackagePush> packagePushList) {
        for (HexagonPackagePush hexagonPackagePush : packagePushList) {
            sendToMes(reqVo, hexagonPackagePush);
        }
    }

    @SneakyThrows
    public void sendToMes(NestProPushHexReqVo reqVo, HexagonPackagePush packagePushList) {
        HexagonPackagePush p = new HexagonPackagePush();
        p.setId(packagePushList.getId());
        p.setStatus(2);
        p.setErrorMsg("");
        p.setResponsePath(null);

        hexagonPackagePushMapper.updateById(p);
        long start = System.currentTimeMillis();

        String requestBody = FileUtils.readFileToString(new File(packagePushList.getRequestPath()), "UTF-8");

        log.info("MES-订单导入-请求：{}",requestBody);

        try (HttpResponse execute = HttpUtil.createPost(mesUrlOrder)
                .contentType("application/xml")
                .header("Accept-Encoding", "gzip, deflate, br")
                .header("Accept", "*/*")
                .body(requestBody, "application/xml")
                .execute()){

            String body = execute.body();

            log.info("MES-订单导入-响应：{}",body);

            String path = FileStorageUtils.getFilePath(FileStorageUtils.NEST_HEXAGON_TYPE);

            FileUtils.writeStringToFile(new File(path), body,"UTF-8");
            p.setResponsePath(path);


            XmlMapper xmlMapper = new XmlMapper();
            JsonNode jsonNode = xmlMapper.readTree(body);
            if(!jsonNode.get("StatusCode").asText().equals("200")){
                p.setStatus(4);
                if(jsonNode.get("ErrorMessage") != null && jsonNode.get("ErrorMessage").asText().length() > 100){
                    p.setErrorMsg(jsonNode.get("ErrorMessage").asText().substring(0, 100));
                } else {
                    p.setErrorMsg(jsonNode.get("ErrorMessage").asText());
                }
            }else {
                p.setStatus(3);
                p.setWorkTime(System.currentTimeMillis() - start);
            }
        } catch (Exception e) {
            e.printStackTrace();
            p.setStatus(4);
            p.setWorkTime(System.currentTimeMillis() - start);
        } finally {
            hexagonPackagePushMapper.updateById(p);
        }

        // 如果有推送中的，就为推送中
        Order order = orderMapper.selectById(packagePushList.getOrderId());

        Integer count = hexagonPackagePushMapper.lambdaQuery()
                .eq(HexagonPackagePush::getOrderId, packagePushList.getOrderId())
                .in(HexagonPackagePush::getStatus, 1,2)
                .count();
        if (count > 0) {
            order.setPushStatus(2);
            orderMapper.updateById(order);
            return ;
        }

        count = hexagonPackagePushMapper.lambdaQuery()
                .eq(HexagonPackagePush::getOrderId, packagePushList.getOrderId())
                .ne(HexagonPackagePush::getStatus, 3)
                .count();
        if (count > 0) {
            order.setPushStatus(4); // 失败
            orderMapper.updateById(order);
        } else {
            order.setPushStatus(3); // 成功
            orderMapper.updateById(order);
        }

        int pushPlanStatus = 0;
        if (p.getStatus() == 3) {
            pushPlanStatus = 4;
        } else if (p.getStatus() == 4) {
            pushPlanStatus = 5;
        }
        sinoCamPushPlanMapper.lambdaUpdate()
//                .eq(SinoCamPushPlan::getApsOrderId, packagePushList.getApsOrderId())
                .eq(SinoCamPushPlan::getPushType, 1)
                .in(SinoCamPushPlan::getNestPlanId, reqVo.getNestPlanId())
                .set(SinoCamPushPlan::getStatus, pushPlanStatus)
                .set(SinoCamPushPlan::getModifyDateTime, LocalDateTime.now())
                .set(SinoCamPushPlan::getModifyUsername, SySecurityUtils.getUserCode())
                .update();

    }

    @Override
    @SneakyThrows
    @Transactional(rollbackFor = Exception.class)
    public void nestReceive(String body) {

        JavaType javaType = objectMapper.getTypeFactory().constructParametricType(List.class, ReceiveNestPlateReqVo.class);
        List<ReceiveNestPlateReqVo> reqVo = objectMapper.readValue(body, javaType);

        receiveNest(reqVo);

    }

    @Transactional(rollbackFor = Exception.class)
    public void receiveNest(List<ReceiveNestPlateReqVo> reqVo) {
        for (ReceiveNestPlateReqVo plateVo : reqVo) {
            ReceiveNestPlateReqVo vo = handleNestResult(plateVo);

            receiveMesNew(vo);

            try {
                // 通知 MES 将钢板状态进行锁定
                UpdateNxolpstatusVo dto = new UpdateNxolpstatusVo();
                dto.setNxolnestixno(plateVo.getNestId());
                apsMesFeign.lockNxolpstatus(dto);
            } catch (Exception e) {
                e.getMessage();
            }
        }
    }

    @SneakyThrows
    @Transactional(rollbackFor = Exception.class)
    public void receiveMesNew(ReceiveNestPlateReqVo reqVo) {

        LogNestExce logNestExce = new LogNestExce();

        Pick pickOne = pickMapper.lambdaQuery().eq(Pick::getPickCode, reqVo.getPickListCode()).one();
        if (pickOne == null) {
            Pick newPick = new Pick();
            newPick.setPickCode(reqVo.getPickListCode());
            newPick.setSendDateTime(LocalDateTime.now());
            newPick.setSendStatus(2);
            newPick.setType(1);
            newPick.setUserCode("000000");
            newPick.setUsername("operator");
            pickMapper.insert(newPick);
        }

        // 查询钢板上零件的推送计划，先锁订单，再锁零件号
        List<ReceiveNestPartReqVo> partList = reqVo.getPart();

        List<SinoCamPushPlan> pushPlanList = sinoCamPushPlanMapper.lambdaQuery()
                .in(SinoCamPushPlan::getProductId, partList.stream().map(ReceiveNestPartReqVo::getConstructNo).collect(Collectors.toList()))
                .in(SinoCamPushPlan::getPartId, partList.stream().map(ReceiveNestPartReqVo::getPartId).collect(Collectors.toList()))
                .orderByAsc(SinoCamPushPlan::getProcessingNo)
                .list();
        if (CollUtil.isEmpty(pushPlanList)) {
            logNestExce.setAppId("MES套料");
            logNestExce.setPlateCode(reqVo.getPlateCode());
            logNestExce.setConstructNo(null);
            logNestExce.setNestId(reqVo.getNestId());
            logNestExce.setPartId("ALL");
            logNestExce.setQuantity(0);
            logNestExce.setNote("未查询到该板零件的推送计划：" + reqVo.getPlateCode());
            logNestExce.setInfoState(0);
            logNestExceMapper.insert(logNestExce);
            return;
        }

        Optional<SinoCamPushPlan> min = pushPlanList.stream().min(Comparator.comparing(SinoCamPushPlan::getNeedDate));
        LocalDateTime needDate = min.get().getNeedDate();
        String needDateTime = needDate.format(DatePattern.NORM_DATETIME_FORMATTER);

        SinoCam sc = new SinoCam();
        sc.setName("5-接收计划");
        sc.setType(5);
        sc.setStatus(1);
        sc.setResult(3);
        sc.setUniNum(sc.getOrderId() + "-" + sc.getType());

        sinoCamMapper.insert(sc);

        SinoCamReceiveNest scrn = new SinoCamReceiveNest();
        scrn.setSinoCamId(sc.getId());
        sinoCamReceiveNestMapper.insert(scrn);

        List<SinoCamReceiveNestPlate> plateAll = new ArrayList<>();
        List<SinoCamReceiveNestNest> nestAll = new ArrayList<>();

        int scId = sc.getId();
        int scrnId = scrn.getId();
        // 套料
        SinoCamReceiveNestNest nn = sinoCamReceiveNestNestMapper.lambdaQuery().eq(SinoCamReceiveNestNest::getNestId, reqVo.getNestId()).one();
        if (nn == null) {
            SinoCamReceiveNestNest nestEntity = MkBeanUtils.copyProperties(reqVo, SinoCamReceiveNestNest.class);
            nestEntity.setSinoCamId(sc.getId());
            nestEntity.setReceiveNestId(scrn.getId());
            nestEntity.setNestId(reqVo.getNestId());
            nestEntity.setFactoryIdk("170");
            nestEntity.setCutNozzleNorm(reqVo.getCutNozzleNorm());
            nestEntity.setCutNozzleNumber(reqVo.getCutNozzleNumber());
            nestEntity.setCutNozzleDistance(reqVo.getCutNozzleDistance());
            nestEntity.setWidth(reqVo.getWidth());
            nestEntity.setLength(reqVo.getLength());
            nestEntity.setNestDate(reqVo.getNestDateTime());
            nestEntity.setChangeDate(reqVo.getChangeDateTime());
            nestEntity.setNeedDate(needDateTime);
            nestEntity.setNester(reqVo.getNester());
            nestEntity.setChanger(reqVo.getChanger());
            nestEntity.setOptionId(reqVo.getGroupCode());
            nestEntity.setSplitGroupCode(reqVo.getGroupCode());
            nestEntity.setNestDxfUrl(mesDXF + reqVo.getDxfUrl());
            LocalDateTime nowDateTime = LocalDateTime.now();
            String nowTime = nowDateTime.format(DatePattern.PURE_DATE_FORMATTER);
            nestEntity.setBookSheet(nowTime);
            nestEntity.setReportPdfUrl(reqVo.getReportPdfUrl());
            nestEntity.setCuttingProgramUrl(reqVo.getCuttingProgramUrl());
            nestEntity.setRate(reqVo.getRate()); // 利用率，钢板减去余料，再与零件重量进行计算，得到利用率
            nestEntity.setVersionBrief("V2");
            sinoCamReceiveNestNestMapper.insert(nestEntity);
            nestAll.add(nestEntity);

            log.info("套料:{}", JsonUtils.toJsonString(nestEntity));
        } else {
            scId = nn.getSinoCamId();
            scrnId = nn.getReceiveNestId();
        }

        // 零件
        List<ReceiveNestPartReqVo> receiveNestParts = reqVo.getPart();
        List<SinoCamReceiveNestPart> receiveParts = new ArrayList<>();

        for (ReceiveNestPartReqVo e : receiveNestParts) {

            if (!StringUtils.hasText(e.getMesOrderCode())) {
                logNestExce.setAppId("MES套料");
                logNestExce.setPlateCode(reqVo.getPlateCode());
                logNestExce.setConstructNo(e.getConstructNo() != null ? e.getConstructNo() : null);
                logNestExce.setNestId(reqVo.getNestId());
                logNestExce.setPartId(e.getPartId());
                logNestExce.setQuantity(e.getQuantity());
                logNestExce.setNote("该零件没有MES施工号：" + e.getPartId());
                logNestExce.setInfoState(0);
                logNestExceMapper.insert(logNestExce);
                continue;
            }

            if (!StringUtils.hasText(e.getMesPkgCode())) {
                logNestExce.setAppId("MES套料");
                logNestExce.setPlateCode(reqVo.getPlateCode());
                logNestExce.setConstructNo(e.getConstructNo() != null ? e.getConstructNo() : null);
                logNestExce.setNestId(reqVo.getNestId());
                logNestExce.setPartId(e.getPartId());
                logNestExce.setQuantity(e.getQuantity());
                logNestExce.setNote("该零件没有MES包号：" + e.getPartId());
                logNestExce.setInfoState(0);
                logNestExceMapper.insert(logNestExce);
                continue;
            }

            HexagonPackagePush hexagonPush = null;
            List<HexagonPackagePush> hexagonPackagePushList = hexagonPackagePushMapper.lambdaQuery()
                    .eq(HexagonPackagePush::getMesOrderCode, e.getMesOrderCode())
                    .eq(HexagonPackagePush::getPackageCode, e.getMesPkgCode())
                    .list();
            if (CollUtil.isNotEmpty(hexagonPackagePushList)) {
                if (hexagonPackagePushList.size() > 1) {
                    throw SyExceptionUtils.e("MES工单号和包号有重复：" + e.getMesOrderCode() + "_" + e.getPackageCode());
                }
                hexagonPush = hexagonPackagePushList.get(0);
            }

            if (hexagonPush == null) {
                logNestExce.setAppId("MES套料");
                logNestExce.setPlateCode(reqVo.getPlateCode());
                logNestExce.setConstructNo(e.getConstructNo() != null ? e.getConstructNo() : null);
                logNestExce.setNestId(reqVo.getNestId());
                logNestExce.setPartId(e.getPartId());
                logNestExce.setQuantity(e.getQuantity());
                logNestExce.setNote("该零件没有推送映射关系：" + e.getPartId());
                logNestExce.setInfoState(0);
                logNestExceMapper.insert(logNestExce);
                continue;
            }

            BigDecimal quantity = BigDecimal.valueOf(e.getQuantity()); // 当前钢板上套的数量

            List<SinoCamPushPlan> plans = sinoCamPushPlanMapper.lambdaQuery()
                    .eq(SinoCamPushPlan::getApsOrderId, hexagonPush.getApsOrderId())
                    .eq(SinoCamPushPlan::getPartId, e.getPartId())
                    .list();

            if (CollUtil.isEmpty(plans)) {
                logNestExce.setAppId("MES套料");
                logNestExce.setPlateCode(reqVo.getPlateCode());
                logNestExce.setConstructNo(e.getConstructNo() != null ? e.getConstructNo() : null);
                logNestExce.setNestId(reqVo.getNestId());
                logNestExce.setPartId(e.getPartId());
                logNestExce.setQuantity(e.getQuantity());
                logNestExce.setNote("该零件未查询到包次推送计划：" + e.getPartId());
                logNestExce.setInfoState(0);
                logNestExceMapper.insert(logNestExce);
                continue;
            }

            for (int index = 0; index < plans.size(); index++) {
                SinoCamPushPlan plan = plans.get(index);
                if (quantity.compareTo(BigDecimal.ZERO) < 1) {
                    continue;
                }
                if (index != plans.size() - 1 && plan.getPlanFinishAmount().compareTo(plan.getPlanAmount()) >= 0) {
                    continue;
                }

                BigDecimal planAmount = plan.getPlanAmount(); // 该计划的需要数量
                BigDecimal planFinishAmount = plan.getPlanFinishAmount(); // 该计划已经套的数量
                BigDecimal amount = planAmount.subtract(planFinishAmount); // 该计划当前所需差值
                if (quantity.compareTo(amount) < 0) {
                    // 该钢板所套数量小于该计划当前的差值，所有数量全部归到该条数据
                    SinoCamReceiveNestPart part = MkBeanUtils.copyProperties(e, SinoCamReceiveNestPart.class);
                    part.setSinoCamId(scId);
                    part.setReceiveNestId(scrnId);
                    part.setNestId(reqVo.getNestId());
                    part.setNestPlanId(plan.getNestPlanId());
                    part.setPartId(plan.getPartId());
                    part.setPartName(e.getPartName());
                    part.setQuantity(quantity.intValue());
                    part.setNetWeight(e.getNetWeight());
                    part.setArea(e.getArea() != null ? e.getArea() : BigDecimal.ZERO);
                    part.setRectangleArea(e.getRectangleArea() != null ? e.getRectangleArea() : BigDecimal.ZERO);
                    part.setRequireFactoryId(e.getFactoryCode());
                    part.setWidth(e.getWidth());
                    part.setLength(e.getLength());
                    if (e.getThickness() == null) {
                        part.setThickness(reqVo.getThickness());
                    } else {
                        part.setThickness(e.getThickness());
                    }
                    part.setPartMapUrl(mesPNG + e.getPngUrl());
                    part.setPlateCode(e.getPlateCode());
                    part.setSortingCount(0);// 分拣数量
                    part.setUniCode(plan.getUniMaterCode());
                    part.setSortState(0);

                    part.setOrderId(plan.getOrderId());
                    part.setWorkOrderCode(e.getWorkOrderCode());
                    part.setMesOrderCode(e.getMesOrderCode());
                    part.setMesPkgCode(e.getMesPkgCode());
                    part.setMesLineId(e.getLineId());

                    plan.setPlanFinishAmount(planFinishAmount.add(quantity));
                    quantity = BigDecimal.ZERO;
                    receiveParts.add(part);
                    plan.setStatus(4);
                    plan.setErrorMsg("已回填数据。");
                    sinoCamPushPlanMapper.updateById(plan);
                } else if (quantity.compareTo(amount) == 0) {
                    // 该钢板所套数量等于该计划当前的差值，所有数量全部归到该条数据，并且修改状态为填充完成
                    SinoCamReceiveNestPart part = MkBeanUtils.copyProperties(e, SinoCamReceiveNestPart.class);
                    part.setSinoCamId(scId);
                    part.setReceiveNestId(scrnId);
                    part.setNestId(reqVo.getNestId());
                    part.setNestPlanId(plan.getNestPlanId());
                    part.setPartId(plan.getPartId());
                    part.setPartName(e.getPartName());
                    part.setQuantity(quantity.intValue());
                    part.setNetWeight(e.getNetWeight());
                    part.setArea(e.getArea() != null ? e.getArea() : BigDecimal.ZERO);
                    part.setRectangleArea(e.getRectangleArea() != null ? e.getRectangleArea() : BigDecimal.ZERO);
                    part.setRequireFactoryId(e.getFactoryCode());
                    part.setWidth(e.getWidth());
                    part.setLength(e.getLength());
                    if (e.getThickness() == null) {
                        part.setThickness(reqVo.getThickness());
                    } else {
                        part.setThickness(e.getThickness());
                    }
                    part.setPartMapUrl(mesPNG + e.getPngUrl());
                    part.setPlateCode(e.getPlateCode());
                    part.setSortingCount(0);// 分拣数量
                    part.setUniCode(plan.getUniMaterCode());
                    part.setSortState(0);

                    part.setOrderId(plan.getOrderId());
                    part.setWorkOrderCode(e.getWorkOrderCode());
                    part.setMesOrderCode(e.getMesOrderCode());
                    part.setMesPkgCode(e.getMesPkgCode());
                    part.setMesLineId(e.getLineId());

                    plan.setPlanFinishAmount(planFinishAmount.add(quantity));
                    quantity = BigDecimal.ZERO;
                    receiveParts.add(part);
                    plan.setConsumeStatus(1);
                    plan.setStatus(4);
                    plan.setErrorMsg("已回填数据。");
                    sinoCamPushPlanMapper.updateById(plan);
                } else if (quantity.compareTo(amount) > 0) {
                    // 该钢板所套数量大于该计划当前的差值，填充该数据所有差值，并且修改状态为填充完成，将该板剩余数量填充下一条数据
                    SinoCamReceiveNestPart part = MkBeanUtils.copyProperties(e, SinoCamReceiveNestPart.class);
                    part.setSinoCamId(scId);
                    part.setReceiveNestId(scrnId);
                    part.setNestId(reqVo.getNestId());
                    part.setNestPlanId(plan.getNestPlanId());
                    part.setPartId(e.getPartId());
                    part.setPartName(e.getPartName());
                    BigDecimal partQuantity = amount;
                    if (index == plans.size() - 1) {
                        partQuantity = quantity;
                        quantity = BigDecimal.ZERO;
                    } else {
                        quantity = quantity.subtract(amount);
                    }
                    part.setQuantity(partQuantity.intValue());
                    part.setNetWeight(e.getNetWeight());
                    part.setArea(e.getArea() != null ? e.getArea() : BigDecimal.ZERO);
                    part.setRectangleArea(e.getRectangleArea() != null ? e.getRectangleArea() : BigDecimal.ZERO);
                    part.setRequireFactoryId(e.getFactoryCode());
                    part.setWidth(e.getWidth());
                    part.setLength(e.getLength());
                    if (e.getThickness() == null) {
                        part.setThickness(reqVo.getThickness());
                    } else {
                        part.setThickness(e.getThickness());
                    }
                    part.setPartMapUrl(mesPNG + e.getPngUrl());
                    part.setPlateCode(e.getPlateCode());
                    part.setSortingCount(0);// 分拣数量
                    part.setUniCode(plan.getUniMaterCode());
                    part.setSortState(0);
                    // part.setQuantity(planAmount.intValue());
                    // quantity = quantity.subtract(amount);
                    receiveParts.add(part);
                    if (index == plans.size() - 1) {
                        plan.setPlanFinishAmount(planFinishAmount.add(partQuantity));
                    } else {
                        plan.setPlanFinishAmount(planAmount);
                    }

                    part.setOrderId(plan.getOrderId());
                    part.setWorkOrderCode(e.getWorkOrderCode());
                    part.setMesOrderCode(e.getMesOrderCode());
                    part.setMesPkgCode(e.getMesPkgCode());
                    part.setMesLineId(e.getLineId());

                    plan.setConsumeStatus(1);
                    plan.setStatus(4);
                    plan.setErrorMsg("已回填数据。");
                    sinoCamPushPlanMapper.updateById(plan);
                }
            }

        }

        if(CollUtil.isNotEmpty(receiveParts)){
            sinoCamReceiveNestPartMapper.insertBatchSomeColumn(receiveParts);
        }

        log.info("零件:{}", JsonUtils.toJsonString(receiveParts));

        // 钢板
        SinoCamReceiveNestPlate plate = MkBeanUtils.copyProperties(reqVo, SinoCamReceiveNestPlate.class);
        BigDecimal bigDecimal = new BigDecimal(1);
        BigDecimal amount = bigDecimal.setScale(0, RoundingMode.HALF_UP);
        plate.setAmount(amount);
        plate.setHeatNumber(reqVo.getHeatId());
        plate.setSinoCamId(scId);
        plate.setReceiveNestId(scrnId);
        plate.setNestId(reqVo.getNestId());
        plate.setStockListNo(reqVo.getPlateCode());
        plate.setMaterielName(reqVo.getPlateCode());
        plate.setFactoryIdk("170");
        plate.setTexture(reqVo.getTexture());
        plate.setNorm(reqVo.getThickness().setScale(0, RoundingMode.HALF_UP).toString());
        plate.setWidth(reqVo.getWidth());
        plate.setLength(reqVo.getLength());
        plate.setStorehouseId(reqVo.getStoreCode());
        plate.setSequence(reqVo.getSequence());
        plate.setLayer(reqVo.getSequence());
        plate.setIsVirtual(false);
        plate.setRate(reqVo.getRate());
        plate.setSideLength(reqVo.getSideLength());
        plate.setStatus(1);// 领料状态
        plate.setPngUrl(mesPNG + reqVo.getPngUrl());
        plate.setPositionCode(reqVo.getPositionCode());
        plate.setNestArea(reqVo.getNxusedarea());

        sinoCamReceiveNestPlateMapper.insert(plate);
        plateAll.add(plate);

        log.info("钢板:{}", JsonUtils.toJsonString(plate));

        // 余料
        List<ReceiveNestExcessReqVo> excessListVo = reqVo.getExcess();
        if (CollUtil.isNotEmpty(excessListVo)) {
            ReceiveNestExcessReqVo excessVo = excessListVo.get(0);
            List<SinoCamReceiveNestExcess> list = sinoCamReceiveNestExcessMapper.lambdaQuery()
                    .eq(SinoCamReceiveNestExcess::getNestId, reqVo.getNestId())
                    .eq(SinoCamReceiveNestExcess::getStockListNo, reqVo.getPlateCode())
                    .eq(SinoCamReceiveNestExcess::getExMaterielId, excessVo.getExcessCode())
                    .list();
            if (CollUtil.isEmpty(list)) {
                SinoCamReceiveNestExcess excess = MkBeanUtils.copyProperties(excessVo, SinoCamReceiveNestExcess.class);
                excess.setSinoCamId(scId);
                excess.setReceiveNestId(scrnId);
                excess.setNestId(reqVo.getNestId());
                excess.setFactoryIdk("170");
                excess.setStockListNo(excessVo.getPlateCode());
                excess.setExMaterielId(excessVo.getExcessCode());
                excess.setTexture(excessVo.getTexture());
                excess.setNorm(excessVo.getThickness().toString());
                excess.setWidth(excessVo.getWidth());
                excess.setLength(excessVo.getLength());
                excess.setWeight(excessVo.getWeight());
                excess.setOutStock(0);
                sinoCamReceiveNestExcessMapper.insert(excess);

                log.info("余料:{}", JsonUtils.toJsonString(excess));
            }
        }

        // 走刀
        List<ReceiveNestMoveReqVo> moveList = reqVo.getMove();
        List<SinoCamReceiveNestMove> moves = new ArrayList<>();
        List<SinoCamReceiveNestMove> nm = sinoCamReceiveNestMoveMapper.lambdaQuery().eq(SinoCamReceiveNestMove::getNestId, reqVo.getNestId()).list();
        if (CollUtil.isEmpty(nm)) {
            if (CollUtil.isNotEmpty(moveList)) {
                int totalTime = 0;
                for (ReceiveNestMoveReqVo vo : moveList) {
                    SinoCamReceiveNestMove move = MkBeanUtils.copyProperties(vo, SinoCamReceiveNestMove.class);
                    move.setSinoCamId(scId);
                    move.setReceiveNestId(scrnId);
                    move.setNestId(reqVo.getNestId());
                    move.setCutLength(vo.getCutLength());
                    move.setFactoryIdk(vo.getFactoryCode());
                    move.setMoveTime(vo.getMoveTime());
                    move.setMoveType(vo.getMoveType());
                    move.setHoleCount(vo.getHoleCount());
                    move.setHoleTime(vo.getHoleTime());
                    move.setTotalHoleTime(vo.getTotalHoleTime());
                    move.setCutRate(vo.getCutRate());
                    move.setTotalCutTime(vo.getTotalCutTime());
                    totalTime = totalTime + vo.getTotalCutTime();
                    moves.add(move);
                }
                for (SinoCamReceiveNestMove a : moves) {
                    a.setTotalCutTime(totalTime);
                }
                sinoCamReceiveNestMoveMapper.insertBatchSomeColumn(moves);
            } else {
                SinoCamReceiveNestMove move1 = new SinoCamReceiveNestMove();
                SinoCamReceiveNestMove move2 = new SinoCamReceiveNestMove();

                move1.setSinoCamId(scId);
                move1.setReceiveNestId(scrnId);
                move1.setNestId(reqVo.getNestId());
                move1.setCutLength(BigDecimal.valueOf(1));
                move1.setFactoryIdk("170");
                move1.setMoveTime(1);
                move1.setMoveType(1);
                move1.setHoleCount(1);
                move1.setHoleTime(1);
                move1.setTotalHoleTime(1);
                move1.setCutRate(BigDecimal.valueOf(1));
                move1.setTotalCutTime(1);
                sinoCamReceiveNestMoveMapper.insert(move1);

                move2.setSinoCamId(scId);
                move2.setReceiveNestId(scrnId);
                move2.setNestId(reqVo.getNestId());
                move2.setCutLength(BigDecimal.valueOf(1));
                move2.setFactoryIdk("170");
                move2.setMoveTime(1);
                move2.setMoveType(2);
                move2.setHoleCount(1);
                move2.setHoleTime(0);
                move2.setTotalHoleTime(0);
                move2.setCutRate(BigDecimal.valueOf(1));
                move2.setTotalCutTime(1);
                sinoCamReceiveNestMoveMapper.insert(move2);

                logNestExce.setAppId("MES套料");
                logNestExce.setPlateCode(reqVo.getPlateCode());
                logNestExce.setConstructNo(receiveNestParts.get(0).getConstructNo());
                logNestExce.setNestId(reqVo.getNestId());
                logNestExce.setPartId(null);
                logNestExce.setQuantity(null);
                logNestExce.setNote("该钢板没有走刀信息！：" + reqVo.getPlateCode());
                logNestExce.setInfoState(0);
                logNestExceMapper.insert(logNestExce);
            }

        }

        List<Integer> planIdList = receiveParts.stream().map(e -> Integer.parseInt(e.getNestPlanId())).distinct().collect(Collectors.toList());
        List<ApsWorkDetail> apsWorkDetails = apsWorkDetailMapper.selectBatchIds(planIdList);

        // ---------- 推送到钢板信息表----
        List<PlatePhase> platePhaseList = new ArrayList<>();
        List<ApsWorkDetail> apsWorkDetailList = new ArrayList<>();
        Map<String, PlatePhase> plateLlPhaseMap = new HashMap<>();
        Plate mesPlate = new Plate();
        List<ReceiveNestPartReqVo> nestParts = reqVo.getPart();
        mesPlate.setMaterCode(reqVo.getPlateCode());// 钢板编号
        mesPlate.setMaterName("钢板");// 钢板物料名称
        mesPlate.setLength(reqVo.getLength());
        mesPlate.setWidth(reqVo.getWidth());
        mesPlate.setNorm(String.valueOf(reqVo.getThickness().setScale(0, RoundingMode.HALF_UP)));// 厚度
        mesPlate.setTexture(reqVo.getTexture());
        mesPlate.setStatus(2);
        mesPlate.setHeatNumber(reqVo.getHeatId());

        SinoCamReceiveNestExcess nestExcess = sinoCamReceiveNestExcessMapper.lambdaQuery().eq(SinoCamReceiveNestExcess::getStockListNo, reqVo.getPlateCode()).one();
        BigDecimal weight = reqVo.getWeight();
        if (nestExcess != null) {
            weight = weight.subtract(nestExcess.getWeight());
        }

        mesPlate.setNestId(reqVo.getNestId());
        mesPlate.setNestRate(reqVo.getRate());// 利用率
        mesPlate.setNestDateTime(LocalDateTime.parse(needDateTime, DatePattern.NORM_DATETIME_FORMATTER));// 套料日期
        mesPlate.setNestingDrawing(mesPNG + reqVo.getPngUrl());// 套料图纸，PNG格式
        mesPlate.setCutProcess(reqVo.getCuttingProgramUrl());// 切割程序下载地址
        mesPlate.setWeight(reqVo.getWeight());
        mesPlate.setNestWeight(weight.multiply(reqVo.getRate().divide(BigDecimal.valueOf(100), 4, RoundingMode.HALF_UP)));
        mesPlate.setPickDateTime(plate.getPickDateTime());// 领料时间
        mesPlate.setNestPlateId(plate.getId());
        mesPlate.setNestLock(0);

        PlatePhase llPhase = new PlatePhase();
        llPhase.setPlateCode(plate.getStockListNo());
        llPhase.setPhaseCode(WorkshopProp.LL_PHASE_CODE);
        llPhase.setPhaseName(WorkshopProp.LL_PHASE_NAME);
        llPhase.setGroupCode(WorkshopProp.LL_GROUP);
        llPhase.setPhaseSeq(platePhaseList.size() + 1);
        platePhaseList.add(llPhase);

        ApsWorkDetail llApsWorkDetail = new ApsWorkDetail();
        llApsWorkDetail.setMaterNo(plate.getStockListNo());
        llApsWorkDetail.setMaterName("钢板");
        llApsWorkDetail.setPhaseId(llPhase.getPhaseSeq());
        llApsWorkDetail.setPhaseSeq(llPhase.getPhaseSeq());
        llApsWorkDetail.setPhaseCode(WorkshopProp.LL_PHASE_CODE);
        llApsWorkDetail.setPartCount(new BigDecimal(1));
        llApsWorkDetail.setFinishCount(new BigDecimal(0));
        llApsWorkDetail.setTotalCount(new BigDecimal(1));
        llApsWorkDetail.setUniqueCode(plate.getStockListNo());
        llApsWorkDetail.setStatus(3);
        llApsWorkDetail.setPhaseName(WorkshopProp.LL_PHASE_NAME);
        llApsWorkDetail.setPlanStartDateTime(LocalDateTime.parse(needDateTime, DatePattern.NORM_DATETIME_FORMATTER).minusHours(7));
        llApsWorkDetail.setActualStartDateTime(LocalDateTime.now());
        llApsWorkDetail.setPlanEndDateTime(LocalDateTime.parse(needDateTime, DatePattern.NORM_DATETIME_FORMATTER).minusHours(6));
        llApsWorkDetail.setGroupCode(WorkshopProp.LL_GROUP);
        llApsWorkDetail.setAppendFlag(2);
        llApsWorkDetail.setType(1);
        llApsWorkDetail.setTotalWorkTime(60 * 60);
        llApsWorkDetail.setWorkTime(60 * 60);
        if (CollUtil.isNotEmpty(apsWorkDetails)) {
            llApsWorkDetail.setOrderId(apsWorkDetails.get(0).getOrderId());
            llApsWorkDetail.setApsOrderId(apsWorkDetails.get(0).getApsOrderId());
        }
        apsWorkDetailList.add(llApsWorkDetail);

        plateLlPhaseMap.put(plate.getStockListNo(), llPhase);

        // 添加预处理工序
        BigDecimal thickness = new BigDecimal(plate.getNorm());
        if (thickness.compareTo(new BigDecimal(100)) < 0) { //钢板厚度小于100走预处理
            PlatePhase phase = new PlatePhase();
            phase.setPlateCode(plate.getStockListNo());
            phase.setPhaseCode(WorkshopProp.YC_PHASE_CODE);
            phase.setPhaseName("预处理");
            phase.setGroupCode(WorkshopProp.YC_GROUP);
            phase.setPhaseSeq(platePhaseList.size() + 1);
            phase.setWorkTime(540);
            platePhaseList.add(phase);

            ApsWorkDetail ycApsWorkDetail = new ApsWorkDetail();
            ycApsWorkDetail.setMaterNo(plate.getStockListNo());
            ycApsWorkDetail.setMaterName("钢板");
            ycApsWorkDetail.setPhaseId(phase.getPhaseSeq());
            ycApsWorkDetail.setPhaseSeq(phase.getPhaseSeq());
            ycApsWorkDetail.setPhaseCode(WorkshopProp.YC_PHASE_CODE);
            ycApsWorkDetail.setPartCount(new BigDecimal(1));
            ycApsWorkDetail.setFinishCount(new BigDecimal(0));
            ycApsWorkDetail.setTotalCount(new BigDecimal(1));
            ycApsWorkDetail.setUniqueCode(plate.getStockListNo());
            ycApsWorkDetail.setStatus(2);
            ycApsWorkDetail.setPhaseName("预处理");
            ycApsWorkDetail.setPlanStartDateTime(LocalDateTime.parse(needDateTime, DatePattern.NORM_DATETIME_FORMATTER).minusHours(7));
            ycApsWorkDetail.setPlanEndDateTime(LocalDateTime.parse(needDateTime, DatePattern.NORM_DATETIME_FORMATTER).minusHours(6));
            ycApsWorkDetail.setGroupCode(WorkshopProp.YC_GROUP);
            ycApsWorkDetail.setAppendFlag(2);
            ycApsWorkDetail.setType(1);
            ycApsWorkDetail.setTotalWorkTime(60 * 60);
            ycApsWorkDetail.setWorkTime(60 * 60);
            if (CollUtil.isNotEmpty(apsWorkDetails)) {
                ycApsWorkDetail.setOrderId(apsWorkDetails.get(0).getOrderId());
                ycApsWorkDetail.setApsOrderId(apsWorkDetails.get(0).getApsOrderId());
            }
            apsWorkDetailList.add(ycApsWorkDetail);
        }

        // 添加切割工序
        PlatePhase splitPhase = new PlatePhase();
        splitPhase.setPlateCode(plate.getStockListNo());
        String phaseCode = getSplitCode(reqVo.getGroupCode());
        splitPhase.setPhaseCode(phaseCode);
        splitPhase.setPhaseName(phaseCode.equals("JG") ? "激光切割" : "火焰切割");
        splitPhase.setGroupCode(reqVo.getGroupCode());
        splitPhase.setPhaseSeq(platePhaseList.size() + 1);
        List<SinoCamReceiveNestMove> nestMoveList = sinoCamReceiveNestMoveMapper.lambdaQuery().eq(SinoCamReceiveNestMove::getNestId, reqVo.getNestId()).list();
        if (CollUtil.isNotEmpty(nestMoveList)) {
            splitPhase.setWorkTime(nestMoveList.get(0).getTotalCutTime());
        } else {
            splitPhase.setWorkTime(0);
        }
        platePhaseList.add(splitPhase);

        ApsWorkDetail qgApsWorkDetail = new ApsWorkDetail();
        qgApsWorkDetail.setMaterNo(plate.getStockListNo());
        qgApsWorkDetail.setMaterName("钢板");
        qgApsWorkDetail.setPhaseId(splitPhase.getPhaseSeq());
        qgApsWorkDetail.setPhaseSeq(splitPhase.getPhaseSeq());
        qgApsWorkDetail.setPhaseCode(phaseCode);
        qgApsWorkDetail.setPartCount(new BigDecimal(1));
        qgApsWorkDetail.setFinishCount(new BigDecimal(0));
        qgApsWorkDetail.setTotalCount(new BigDecimal(1));
        qgApsWorkDetail.setUniqueCode(plate.getStockListNo());
        qgApsWorkDetail.setStatus(2);
        qgApsWorkDetail.setPhaseName(phaseCode.equals("JG") ? "激光切割" : "火焰切割");
        qgApsWorkDetail.setPlanStartDateTime(LocalDateTime.parse(needDateTime, DatePattern.NORM_DATETIME_FORMATTER));
        qgApsWorkDetail.setPlanEndDateTime(LocalDateTime.parse(needDateTime, DatePattern.NORM_DATETIME_FORMATTER).plusHours(2));
        qgApsWorkDetail.setGroupCode(reqVo.getGroupCode());
        qgApsWorkDetail.setAppendFlag(2);
        qgApsWorkDetail.setType(1);
        if (CollUtil.isNotEmpty(apsWorkDetails)) {
            qgApsWorkDetail.setOrderId(apsWorkDetails.get(0).getOrderId());
            qgApsWorkDetail.setApsOrderId(apsWorkDetails.get(0).getApsOrderId());
        }
        qgApsWorkDetail.setTotalWorkTime(2 * 60 * 60);
        qgApsWorkDetail.setWorkTime(2 * 60 * 60);
        apsWorkDetailList.add(qgApsWorkDetail);

        // 添加分捡工序
        Map<String, String> fjGroup = new HashMap<>();
        fjGroup.put("1-1_HYQG_00", "1-1_RGFJ_00");
        fjGroup.put("1-2_JGQG_00", "1-2_ZDFJ_00");
        fjGroup.put("1-3_JGQG_00", "1-3_ZDFJ_00");

        PlatePhase fjPhase = new PlatePhase();
        fjPhase.setPlateCode(plate.getStockListNo());
        fjPhase.setPhaseCode(WorkshopProp.FJ_PHASE_CODE);
        fjPhase.setPhaseName("分捡");
        fjPhase.setGroupCode(fjGroup.get(reqVo.getGroupCode()));
        fjPhase.setPhaseSeq(platePhaseList.size() + 1);
        platePhaseList.add(fjPhase);

        ApsWorkDetail fjApsWorkDetail = new ApsWorkDetail();
        fjApsWorkDetail.setMaterNo(plate.getStockListNo());
        fjApsWorkDetail.setMaterName("钢板");
        fjApsWorkDetail.setPhaseId(fjPhase.getPhaseSeq());
        fjApsWorkDetail.setPhaseSeq(fjPhase.getPhaseSeq());
        fjApsWorkDetail.setPhaseCode(WorkshopProp.FJ_PHASE_CODE);
        fjApsWorkDetail.setPartCount(new BigDecimal(1));
        fjApsWorkDetail.setFinishCount(new BigDecimal(0));
        fjApsWorkDetail.setTotalCount(new BigDecimal(1));
        fjApsWorkDetail.setUniqueCode(plate.getStockListNo());
        fjApsWorkDetail.setStatus(2);
        fjApsWorkDetail.setPhaseName("分捡");
        fjApsWorkDetail.setPlanStartDateTime(LocalDateTime.parse(needDateTime, DatePattern.NORM_DATETIME_FORMATTER).plusHours(2));
        fjApsWorkDetail.setPlanEndDateTime(LocalDateTime.parse(needDateTime, DatePattern.NORM_DATETIME_FORMATTER).plusHours(5));
        fjApsWorkDetail.setGroupCode(fjGroup.get(reqVo.getGroupCode()));
        fjApsWorkDetail.setAppendFlag(2);
        fjApsWorkDetail.setType(1);

        fjApsWorkDetail.setTotalWorkTime(3 * 60 * 60);
        fjApsWorkDetail.setWorkTime(3 * 60 * 60);
        if (CollUtil.isNotEmpty(apsWorkDetails)) {
            fjApsWorkDetail.setOrderId(apsWorkDetails.get(0).getOrderId());
            fjApsWorkDetail.setApsOrderId(apsWorkDetails.get(0).getApsOrderId());
        }
        apsWorkDetailList.add(fjApsWorkDetail);

        mesPlate.setWorkChain(platePhaseList.stream().map(PlatePhase::getPhaseCode).collect(Collectors.joining("-")));

        plateMapper.insert(mesPlate);
        plateLlPhaseMap.forEach(this::makeLingliao);
        Plate plateId = plateMapper.lambdaQuery().eq(Plate::getMaterCode, mesPlate.getMaterCode()).one();
        for (PlatePhase platePhase : platePhaseList) {
            platePhase.setPlateId(plateId.getId());
        }
        platePhaseMapper.insertBatch(platePhaseList);

        apsWorkDetailMapper.insertBatchSomeColumn(apsWorkDetailList);

        WmsPlatePick pick = new WmsPlatePick();

        pick.setPlateState(2);
        pick.setNextWorkPlace(reqVo.getGroupCode());
        pick.setNestPlateId(plate.getId());
        pick.setAmount(1);// 数量
        pick.setLength(plate.getLength());
        pick.setWidth(plate.getWidth());
        pick.setFastFlag(0);
        pick.setReceiveDate(LocalDateTime.now());
        pick.setPlannedStartTime(plate.getPickDateTime());// 领料时间
        pick.setType(1);
        pick.setMaterialCode(plate.getStockListNo());// 厚度
        pick.setPlateMaterial(plate.getTexture());
        pick.setPlateThick(plate.getNorm());// 厚度
        pick.setMaterialId(plate.getStockListNo());// 钢板编号（钢板物料号/材料编号？）
        pick.setPlateUsage(plate.getRate());// 利用率
        pick.setNesting(mesPNG + reqVo.getPngUrl());// 套料图号
        pick.setMaterName(plate.getMaterielName());// 钢板物料名称

        pick.setPickingListNo(reqVo.getPickListCode());
        pick.setPlanDate(null);
        pick.setPackageSn(null);
        pick.setWantDeliverDate(null);
        pick.setStoragePlace(plate.getPositionCode());
        pick.setSeq(plate.getSequence());
        pick.setPickListItem(reqVo.getPickNo());
        pick.setPlateWeight(mesPlate.getWeight());// 钢板重量
        pick.setCloutWeight(null);
        pick.setOutTime(LocalDateTime.now());
        pick.setPlateNote(null);
        pick.setPlateId(mesPlate.getId());// 钢板ID
        pick.setPlannedStartTime(LocalDateTime.parse(needDateTime, DatePattern.NORM_DATETIME_FORMATTER));// 需求日期
        pick.setNestId(reqVo.getNestId());
        pick.setPickDateTime(LocalDateTime.now());

        Pick standarfPick = pickMapper.lambdaQuery().eq(Pick::getPickCode, reqVo.getPickListCode()).one();
        pick.setPickId(standarfPick.getId());

        wmsPlatePickMapper.insert(pick);

        List<SinoCamPushDrawing> pushDrawingList = sinoCamPushDrawingMapper.lambdaQuery()
                .in(SinoCamPushDrawing::getProjectId, receiveNestParts.stream().map(ReceiveNestPartReqVo::getConstructNo).collect(Collectors.toList()))
                .in(SinoCamPushDrawing::getPartId, receiveNestParts.stream().map(ReceiveNestPartReqVo::getPartId).collect(Collectors.toList()))
                .list();
        for (SinoCamPushDrawing e : pushDrawingList) {
            e.setStatus(4);
            e.setErrorMsg("已回填图纸数据。");
            sinoCamPushDrawingMapper.updateById(e);
        }

    }

    public void makeLingliao(String materCode, PlatePhase llPhase) {
        Plate plate = plateMapper.lambdaQuery().eq(Plate::getMaterCode, materCode).one();
        SinoCamReceiveNestPlate nestPlate = sinoCamReceiveNestPlateMapper.lambdaQuery().eq(SinoCamReceiveNestPlate::getStockListNo, materCode).one();
        List<SinoCamReceiveNestPart> nestParts = sinoCamReceiveNestPartMapper.lambdaQuery().eq(SinoCamReceiveNestPart::getPlateCode, materCode).list();
        List<ApsWorkDetail> apsWorkDetails = apsWorkDetailMapper.selectBatchIds(nestParts.stream().map(SinoCamReceiveNestPart::getNestPlanId).distinct().collect(Collectors.toList()));
        List<Integer> orderIds = apsWorkDetails.stream().map(ApsWorkDetail::getOrderId).distinct().collect(Collectors.toList());
        WorkDetailTask plateTask = new WorkDetailTask();
        plateTask.setMaterCode(plate.getMaterCode());
        plateTask.setMaterName(plate.getMaterName());
        plateTask.setPhaseCode(llPhase.getPhaseCode());
        plateTask.setPhaseName(llPhase.getPhaseName());
        plateTask.setGroupCode(llPhase.getGroupCode());
        plateTask.setStationCode(WorkshopProp.LL_STATION_FIRST);
        plateTask.setStatus(2);
        plateTask.setType(1);
        plateTask.setPlanStartDateTime(plate.getNestDateTime());
        plateTask.setPlanEndDateTime(plateTask.getPlanStartDateTime().plusHours(2));
        if (!CollectionUtils.isEmpty(orderIds)) {
            List<Order> orders = orderMapper.selectBatchIds(orderIds);
            plateTask.setOrderCode(orders.stream().map(Order::getConstructNo).distinct().collect(Collectors.joining(",")));
        }
        plateTask.setNorm(plate.getNorm());
        plateTask.setTexture(plate.getTexture());
        plateTask.setWeight(plate.getNestWeight());
        plateTask.setNestPlateId(nestPlate.getId());
        plateTask.setNestId(plate.getNestId());

        plateTask.setPlmid(plate.getMaterCode());
        plateTask.setTotalCount(1);
        plateTask.setNextGroupCode(WorkshopProp.YC_GROUP);
        plateTask.setNextPhaseCode(WorkshopProp.YC_PHASE_CODE);
        plateTask.setPlateCode(plate.getMaterCode());
        plateTask.setLength(plate.getLength());
        plateTask.setWidth(plate.getWidth());
        plateTask.setThickness(BigDecimal.valueOf(Integer.parseInt(plate.getNorm())));
        workDetailTaskMapper.insert(plateTask);
    }

    public String getSplitCode(String optionId) {

        Map<String, String> params = new HashMap<>();
        params.put("1-1_HYQG_00", "HG");
        params.put("1-2_JGQG_00", "JG");
        params.put("1-3_JGQG_00", "JG");

        String groupCode = params.get(optionId);
        if (groupCode == null) {
            throw SyExceptionUtils.e("未知的切割工作组：{}", optionId);
        }

        return groupCode;
    }

    public ReceiveNestPlateReqVo handleNestResult(ReceiveNestPlateReqVo plateVo) {
        try {
            List<ReceiveNestPartReqVo> partListVo = plateVo.getPart();
            List<ReceiveNestExcessReqVo> excessListVo = plateVo.getExcess();
            List<ReceiveNestMoveReqVo> moveListVo = plateVo.getMove();

            plateVo.setFactoryCode("170");
            plateVo.setStoreCode("170");
            BigDecimal plateWeight = PlateWeightUtils.getPlateWeight(plateVo.getLength(), plateVo.getWidth(), plateVo.getThickness());
            plateVo.setWeight(plateWeight);
            plateVo.setDxfUrl(NestInfoChangeUtil.addDxf(plateVo.getNestId()));
            plateVo.setCuttingProgramUrl(plateVo.getNestId());
            plateVo.setPngUrl(NestInfoChangeUtil.replacePng(plateVo.getPngUrl(), ".png"));
            plateVo.setThickness(plateVo.getThickness() != null ? plateVo.getThickness() : BigDecimal.ZERO);
            plateVo.setSideLength(plateVo.getSideLength() != null ? plateVo.getSideLength() : BigDecimal.ZERO);

            for (ReceiveNestPartReqVo vo : partListVo) {
                vo.setFactoryCode("170");
                vo.setPngUrl(NestInfoChangeUtil.replacePng(vo.getPngUrl(), ".png"));
                vo.setThickness(vo.getThickness() != null ? vo.getThickness() : plateVo.getThickness());
                vo.setArea(vo.getArea() != null ? vo.getArea() : BigDecimal.ZERO);
                vo.setRectangleArea(vo.getRectangleArea() != null ? vo.getRectangleArea() : BigDecimal.ZERO);
            }

            if (CollUtil.isNotEmpty(excessListVo)) {
                ReceiveNestExcessReqVo excessVo = excessListVo.get(0);
                excessVo.setFactoryCode("170");
                excessVo.setTexture(excessVo.getTexture() != null ? excessVo.getTexture() : plateVo.getTexture());
                excessVo.setThickness(excessVo.getThickness() != null ? excessVo.getThickness() : plateVo.getThickness());
                excessVo.setWeight(excessVo.getWeight() != null ? excessVo.getWeight() : BigDecimal.ZERO);
            }

            if (CollUtil.isNotEmpty(moveListVo)) {
                for (int i = 0; i < moveListVo.size(); i++) {
                    ReceiveNestMoveReqVo vo = moveListVo.get(i);
                    vo.setCutRate(vo.getCutRate() != null ? vo.getCutRate() : BigDecimal.ZERO);
                    vo.setFactoryCode("170");
                    if (vo.getMoveCode().equals("切割路径")) {
                        vo.setMoveType(1);
                    } else if (vo.getMoveCode().equals("空程路径")) {
                        vo.setMoveType(2);
                    } else {
                        moveListVo.remove(i);
                        i--;
                    }
                }
            }

            plateVo.setPart(partListVo);
            plateVo.setExcess(excessListVo);
            plateVo.setMove(moveListVo);

            return plateVo;
        } catch (Exception e) {
            e.printStackTrace();
            LogNestExce logNestExce = new LogNestExce();
            logNestExce.setAppId("MES套料");
            logNestExce.setPlateCode(plateVo.getPlateCode());
            logNestExce.setConstructNo(null);
            logNestExce.setNestId(plateVo.getNestId());
            logNestExce.setPartId(null);
            logNestExce.setQuantity(0);
            logNestExce.setNote("该钢板套料信息处理异常：" + plateVo.getPlateCode());
            logNestExce.setInfoState(0);
            logNestExceMapper.insert(logNestExce);
            throw SyExceptionUtils.e("套料信息处理异常：{}", plateVo.getPlateCode());
        }
    }

    @Override
    public NestReceiveReqVo nestReceiveNew(String body) {
        return null;
    }

}
